home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Periodicals / develop / develop 3 code / Meet PrGeneral / PrGeneralPlayPrint.c < prev   
Encoding:
C/C++ Source or Header  |  1990-06-08  |  28.9 KB  |  937 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. #
  3. #    PrGeneralPlayPrint.c
  4. #
  5. #   This file contains all of the functions that are used at print time and the 
  6. #   calls to set the requested PrGeneral opcodes selected by the user via the 
  7. #    PrGeneral menu.
  8. #   
  9. #    We will test for the presence of PrGeneral at init time and any time the user
  10. #    changes the printer driver.  If PrGeneral is NOT available for the current 
  11. #    printer driver, the printer driver will return resNotFound in PrError. We 
  12. #   will disable the PrGeneral menu and call PrSetError(0), which will remove the 
  13. #    resNotfound error and allow PrGeneralPlay to print without using PrGeneral's
  14. #    opcodes.  We will set the gPrGeneralLives flag to false which will prevent us
  15. #   from calling any of PrGeneral's opcodes.
  16. #
  17. #    We assume that all of PrGeneral's opcodes are supported by the current printer
  18. #    driver until we determine otherwise.  If we try to use an unsupported opcode, 
  19. #    PrGeneral will set iError to OpNotImpl.  We will then set one of the appropriate 
  20. #    flags (gLandscapeOpImpl, gDraftBitsOpImpl,or gSetRslOpImpl) to "false" to prevent 
  21. #    continued use of this opcode and adjust the PrGeneral menu appropriately.  These 
  22. #     flags will be reset, if the user selects a new printer driver.
  23. #
  24. #   If the "high resolution printing" menu item is selected, we use the GetRslData
  25. #    opcode to determine the highest "square" resolution that is supported by the 
  26. #    current printer driver.  Before we call SetRsl to set these new resolutions, 
  27. #     we will save the original resolutions (in gOriginaliVRes and gOriginaliHRes)
  28. #   which will enable us to reset the resolutions to their original settings, when
  29. #     the user turns "off" this menu item. 
  30. #
  31. #   When the user selects the "forced draft mode printing" menu item, we will create 
  32. #    an off-screen world, call drawStuff to draw our graph into it, and CopyBits the 
  33. #    contents into the printer's GrafPort.  This will ensure that graph will print in 
  34. #    "draft" mode.  Remember, when the DraftBits opcode is used, you will only be able 
  35. #    to print text, bitmaps, and pixmaps.  
  36. #
  37. #    When the "forced draft mode printing" menu item is turned "off", we use the 
  38. #    NoDraftBits opcode to turned off the effects of the DraftBits opcode.
  39. #
  40. #   If the user has selected the "check for landscape orientation" menu item, we will
  41. #   check to determine, if the landscape orientation was selected in the stlye dialog.  
  42. #    We will present the results of the landscape orientation check (GetRotn opcode) 
  43. #   via a dialog.  We will only check for landscape orientation after the user calls 
  44. #   the Page Setup dialog.
  45. #   
  46. #    If any print error occurs during print time, we will call the AlertUser
  47. #    function.  This function will display an alert to tell the user that an
  48. #    error occurred.  This function is NOT how a "real" application should 
  49. #   handle printing errors, but it is the simplest approach possible for this
  50. #    type of application.  Our intent is to demonstrate the use of PrGeneral, 
  51. #    not to create a full featured application.  Tech Note #161 contains an
  52. #   industrial strength full featured printing loop.
  53. #
  54. # ------------------------------------------------------------------------------  
  55. #
  56. #    Versions:   1.00                    June 1, 1990
  57. #
  58. #    Components: PrGeneralPlay.c            June 1, 1990
  59. #                PrGeneralPlayPrint.c    June 1, 1990
  60. #                PrGeneralPlay.h            June 1, 1990
  61. #                PrGeneralPlay.r            June 1, 1990
  62. #
  63. #
  64. #    Apple Macintosh Developer Technical Support
  65. #    Copyright © 1990 Apple Computer, Inc.
  66. #    All rights reserved.
  67. #
  68. ------------------------------------------------------------------------------*/
  69.  
  70. #include <Errors.h>
  71. #include <Types.h>
  72. #include <Resources.h>
  73. #include <ToolUtils.h>
  74. #include <QuickDraw.h>
  75. #include <QDOffscreen.h>
  76. #include <Fonts.h>
  77. #include <Printing.h>
  78. #include <Packages.h>
  79. #include <Memory.h>
  80. #include <sane.h>
  81. #include <PrGeneralPlay.h>
  82.  
  83. //  The following extern globals are set up by the Initialize function in PrGeneralPlay.c
  84.  
  85. extern THPrint            gPrRecHdl;
  86. extern Boolean            gHighResolutionON,  
  87.                         gUseDraftBits,
  88.                         gCheckForLandscape,
  89.                         gDraftBitsHasBeenSet;
  90.                         gPrGeneralLives,
  91.                         gLandscapeOpImpl,
  92.                         gDraftBitsOpImpl,
  93.                         gSetRslOpImpl;
  94.  
  95. extern short            gOriginalDriverVers;
  96.                         
  97. short                      gScale = 1,
  98.                         gMaxDPI = 0,
  99.                         gOriginaliVRes,
  100.                         gOriginaliHRes;
  101.  
  102.  
  103. void noPrGeneralAlert ( void );
  104. Boolean testForPrGeneral ( void );
  105. void saveResolution ( void );
  106. void resetSetRsl ( void );
  107. int setMaxResolution ( void );
  108. void doSetRsl ( void );
  109. void doDraftBits ( void );
  110. void doNODraftBits ( void );
  111. void drawStuff (GrafPtr    prPort, short gScale);
  112. void copyBitsMyGraph (TPPrPort printPort);
  113. void comparePrintRecords ( void );
  114. void PresentStyleDialog ( void );
  115. void PrintThis( void );
  116.  
  117.  
  118. //------ noPrGeneralAlert -----------------------------------------------------------
  119. //
  120. //  Display the alert that tells the user that PrGeneral is not available
  121. //  for the currently selected printer driver...
  122. //
  123.  
  124. void noPrGeneralAlert ()
  125. {
  126.     short        itemHit;
  127.  
  128.     SetCursor(&qd.arrow);
  129.     
  130.     itemHit = NoteAlert(rNOPrGeneralAlert, nil);
  131. }  //  end of noPrGeneralAlert
  132.  
  133.  
  134.  
  135.  
  136. //------ testForPrGeneral -----------------------------------------------------------
  137. //
  138. //  We want to determine if PrGeneral is available.  If it is not, the printer driver
  139. //  will return resNotFound in PrError.  We will then clear the error in PrError with
  140. //  PrSetError (0) and proceed with printing without PrGeneral's opcodes.  If we did not
  141. //  clear the error, you would receive the error in PrError when it was checked, thereby
  142. //  preventing your app from printing.
  143.  
  144. Boolean testForPrGeneral ()
  145. {
  146.       TGetRotnBlk    GetRotRec;
  147.       short          printErr = 0;
  148.   
  149.     GetRotRec.iOpCode = getRotnOp;    // We will test for PrGeneral with the landscape opcode...
  150.     GetRotRec.hPrint = gPrRecHdl;
  151.  
  152.       PrGeneral ((Ptr) &GetRotRec);    
  153.   
  154.       printErr = PrError ();
  155.   
  156.       if (printErr == noErr)            //  PrGeneral is supported by the current driver...
  157.       return (true);
  158.       else 
  159.       {
  160.        if (printErr == resNotFound)
  161.          {
  162.            PrSetError (noErr);        // Since PrGeneral is not available, we want to clear PrError,
  163.            noPrGeneralAlert ();       // which will enable your app to keep printing without
  164.            return (false);            // PrGeneral's opcodes...
  165.          }
  166.        else 
  167.         {
  168.           PrClose ();
  169.           AlertUser ();               // Another type of print error occurred, therefore AlertUser
  170.         }
  171.       }
  172. }  //  end of testForPrGeneral
  173.  
  174.  
  175.  
  176. //------ saveResolution -------------------------------------------------------------
  177. //
  178. //    We need to save the original resolution of the current printer driver, which will
  179. //    enable us to reset the resolutiuon if the user turns the "high resolution" printing
  180. //    menu item "off".
  181. //
  182.  
  183. void saveResolution ()
  184. {
  185.     gOriginaliVRes = (**gPrRecHdl).prInfo.iVRes;
  186.     gOriginaliHRes = (**gPrRecHdl).prInfo.iHRes;
  187. }
  188.  
  189.  
  190.  
  191. //------ resetSetRsl ----------------------------------------------------------------
  192. //
  193. //    resetSetRsl will reset the resolution of the print handle, back to it's orginal 
  194. //    before using the SetRsl opcode.  If the user has not changed the printer, we 
  195. //    will reset the resolution of the printer driver with a call to the SetRsl opcode 
  196. //  with the orginal resolutions that were saved by the function saveResolution. If 
  197. //  the user has selected a different printer via the Chooser, we will call PrintDefault 
  198. //  on our print record.  
  199. //
  200.  
  201. void resetSetRsl ()
  202. {
  203.     TSetRslBlk    setResRec;
  204.     THPrint     localPrRecHdl;
  205.     short        latestDriverVers;
  206.  
  207.     //  Create a "new" print record to compare with...
  208.     
  209.     localPrRecHdl = (THPrint) NewHandle(sizeof(TPrint));
  210.     if (MemError() == noErr && localPrRecHdl != nil)
  211.     {
  212.         PrintDefault (localPrRecHdl);
  213.     
  214.         latestDriverVers = PrDrvrVers ();
  215.     
  216.         //     We need to determine if the user changed the printer driver via Chooser.  
  217.         //    Which would be a problem because the resolutions might not match across 
  218.         //    different printer drivers. We also check to see if the version number has 
  219.         //    changed, which will insure that the user did not change the printer driver
  220.         //    to a different printer driver version.  This is important, because earlier
  221.         //    versions of the ImageWriter (i.e. before v2.5) did not support PrGeneral.
  222.         //  If they have changed the printer driver, call PrintDefault on our global print 
  223.         //  record handle to update it.
  224.         
  225.         if ((((**gPrRecHdl).prStl.wDev) >> 8) == (((**localPrRecHdl).prStl.wDev) >> 8)
  226.              || (latestDriverVers == gOriginalDriverVers))
  227.           {
  228.             //    Reset the print record to the original resolutions...
  229.             
  230.             setResRec.iOpCode = setRslOp;
  231.             setResRec.hPrint = gPrRecHdl;
  232.     
  233.             setResRec.iXRsl = gOriginaliHRes;
  234.             setResRec.iYRsl = gOriginaliVRes;
  235.             
  236.              
  237.             // We do not need to check any PrGeneral errors. Why? We know that this opcode 
  238.             // is supported and we are not using an unsupported resolution...
  239.             
  240.             PrGeneral ((Ptr)(&setResRec));     
  241.     
  242.             gScale = 1;
  243.             gMaxDPI = gOriginaliHRes;                
  244.     
  245.             if (PrError () != noErr)
  246.              {
  247.                PrClose ();          //  We received an error in PrError after calling PrGeneral.
  248.                AlertUser ();        //  Therefore, close the Print Manager and alert the user.
  249.              }
  250.           }
  251.          else  PrintDefault (gPrRecHdl);    
  252.             
  253.         if (localPrRecHdl != nil)  DisposHandle((Handle) localPrRecHdl);
  254.     }
  255.  
  256.         // An error occurred allocating new print record, close the Print Manager and alert the user
  257.     else
  258.     {
  259.         PrClose ();
  260.         AlertUser();
  261.     }
  262.  
  263. }    //  end of resetSetRsl
  264.  
  265.  
  266.  
  267.  
  268. //------ setMaxResolution -----------------------------------------------------------
  269. //
  270. //    setMaxResolution will find the highest "square" resolution supported by the currently 
  271. //    selected printer driver and set the Print Manager's GrafPort to this resolution. 
  272. //    This will enable high resolution printing using the standard Quickdraw calls.  We
  273. //    will return the resolution that is found by our calls to GetRslData.  If the 
  274. //    GetRslData and/or SetRsl opcodes are not supported by the currently selected printer
  275. //    driver, we will return 0.  Which tells the calling function that it must use a
  276. //    scale factor of 1 and assume no SetRsl support
  277. //
  278.  
  279. int setMaxResolution ()
  280. {
  281.      int            resIndex;
  282.      
  283.      TGetRslBlk    getResRec;
  284.      TSetRslBlk    setResRec;
  285.  
  286.     //    Save the current resolution values from the iVRes and iHres fields from 
  287.     //  the PrJob record; which enables us to reset the print handle with the original 
  288.     //  values, if the user un-checks the "high resolution" menu item.
  289.     
  290.     saveResolution ();   
  291.  
  292.      getResRec.iOpCode = getRslDataOp;
  293.      PrGeneral ((Ptr)(&getResRec));    
  294.      
  295.      //    We have an array of possible resolutions.
  296.     //  After checking for errors, we loop through each resolution 
  297.      //    range record looking for the highest resolution available, where x and
  298.      //    y are equal. This loop makes no assumptions about the order of the 
  299.      //    resolution records. Find the maximum resolution supported by the current selected device.
  300.      //    Some devices support non-square aspect ratios (i.e. x-res != y-res), we
  301.      //    need to find the largest "square" resolution supported.  The last rgRslRec is
  302.     //  the "highest" supported resolution record for all of the Apple printer drivers.
  303.     
  304.      if (getResRec.iError == noErr && PrError() == noErr)
  305.        {
  306.         for (resIndex = 0; resIndex < getResRec.iRslRecCnt ; resIndex++)
  307.            {
  308.              if ( getResRec.rgRslRec[resIndex].iXRsl ==
  309.                    getResRec.rgRslRec[resIndex].iYRsl && 
  310.                    getResRec.rgRslRec[resIndex].iXRsl > gMaxDPI)
  311.                   
  312.                gMaxDPI = getResRec.rgRslRec[resIndex].iYRsl;
  313.             }
  314.            
  315.         //  We now have the desired resolution. If it is not 0, then we
  316.        //  use the SetRsl opcode to set the resolution.
  317.  
  318.        if (gMaxDPI != 0 && gPrRecHdl != nil)
  319.            {
  320.             setResRec.iOpCode = setRslOp;
  321.             setResRec.hPrint = gPrRecHdl;
  322.  
  323.             setResRec.iXRsl = gMaxDPI;
  324.             setResRec.iYRsl = gMaxDPI;
  325.          
  326.              PrGeneral ((Ptr)(&setResRec));    
  327.            }
  328.       }
  329.      //     If the current printer driver does NOT support GetRslData set the flag
  330.      //  and return 0, which tells the calling function to use a scale factor of 1.
  331.      
  332.      else if (getResRec.iError == OpNotImpl)   
  333.            {
  334.              gSetRslOpImpl = false;
  335.              return (0);
  336.            }
  337.           else AlertUser (); 
  338.  
  339.  
  340.      //    If our call to SetRsl worked return the "new" resolution, otherwise
  341.     //    check to see if this opcode is implemented.  If it is not return 0 
  342.     //    and set our SetRslOpImpl flag to false.  
  343.     
  344.     if (setResRec.iError == noErr && PrError() == noErr && gMaxDPI != 0)
  345.           return (gMaxDPI);
  346.     else if (setResRec.iError == OpNotImpl && PrError() == noErr)
  347.            {
  348.              gSetRslOpImpl = false;
  349.              return (0);
  350.            }
  351.          else return (0);
  352.  
  353. }    //  end of setMaxResolution
  354.  
  355.  
  356.  
  357.     
  358. //------ doSetRsl -------------------------------------------------------------------
  359. //
  360. //  doSetRsl is the calling function that calls setMaxResolution.  setMaxResolution
  361. //    will return the maximum resolution that is supported by the current printer
  362. //    driver.  With this device resolution (deviceRes), we will then determine the scale
  363. //    factor that must be used on all of our coordinates and font sizes, otherwise
  364. //    we will receive "micro" text and images.  If setMaxresolution returns 0, it means 
  365. //    that SetRsl and GetRslData are not supported or an error occurred.  We will then
  366. //    use a scale factor of 1.
  367. //
  368.  
  369. void doSetRsl ()
  370. {
  371.     short        deviceRes;
  372.     GrafPtr        oldPort;
  373.     
  374.     GetPort (&oldPort);
  375.  
  376.     deviceRes = setMaxResolution ();
  377.      
  378.     //    If deviceRes is not zero, we will determine the scale factor that
  379.     //    MUST be used on all of our coordinates and font sizes.  If we do 
  380.     //    NOT scale these items, we will get the "micro" text and images...
  381.     
  382.     if (deviceRes != 0) gScale = deviceRes / MacScreenRes;
  383.  
  384.     SetPort (oldPort);
  385.  
  386. }    //     end of doSetRsl
  387.  
  388.  
  389.  
  390.  
  391. //------ doDraftBits ----------------------------------------------------------------
  392. //
  393. //    doDraftBits will set the draftBitsOp opcode for the current printer driver.  If the 
  394. //    current printer driver does NOT support this opcode, we will set the gDraftBitsOpImpl
  395. //    flag to false which will prevent this function from being called.  If any error occurs,
  396. //    we will alert the user via the AlertUser function.
  397. //
  398.  
  399. void doDraftBits ()
  400. {
  401.     TDftBitsBlk        draftBitsBlk;
  402.  
  403.     gDraftBitsHasBeenSet = true;
  404.  
  405.     //  Set the draftBitsOp and update the contents of the print handle.
  406.     
  407.     draftBitsBlk.iOpCode = draftBitsOp;
  408.     draftBitsBlk.hPrint = gPrRecHdl;
  409.     PrGeneral((Ptr) &draftBitsBlk);
  410.  
  411.     //  The draftBits opcode is NOT supported by the current printer driver,
  412.     //  therefore we will set the draftBits opcode implemented flag to false.
  413.     //  Which will prevent this function from being called until a new printer 
  414.     //  is selected via the Chooser.  If another type of error occurred report
  415.     //  it to the user via AlertUser.
  416.  
  417.     if (draftBitsBlk.iError == OpNotImpl && PrError() == noErr)
  418.       gDraftBitsOpImpl  = false; 
  419.     else if (draftBitsBlk.iError != noErr || PrError() != noErr)
  420.            AlertUser ();
  421.      
  422. }  // end of doDraftBits
  423.  
  424.  
  425.  
  426.  
  427. //------ doNODraftBits ---------------------------------------------------------------
  428. //
  429. //    doNODraftBits will undo the call to set the draftBitsOp opcode.  This function can
  430. //  NOT be called if doDraftBits was not called or this opcode is not supported by the 
  431. //    current printer driver.  This function behaves in the same manner as described above
  432. //  for doDraftBits.
  433. //
  434.  
  435. void doNODraftBits ()
  436. {
  437.     TDftBitsBlk        draftBitsBlk;
  438.  
  439.     draftBitsBlk.iOpCode = noDraftBitsOp;
  440.     draftBitsBlk.hPrint = gPrRecHdl;
  441.     PrGeneral((Ptr) &draftBitsBlk);
  442.  
  443.     if (draftBitsBlk.iError != noErr || PrError() != noErr)
  444.        AlertUser ();
  445.  
  446. }  // end of doNODraftBits
  447.  
  448.  
  449.  
  450.  
  451. //------ ShowLandscapeResults --------------------------------------------------------
  452. //
  453. //    This routine will show the results via a dialog of the IsLandscapeSet function.
  454. //
  455.  
  456. void ShowLandscapeResults (Boolean result)
  457.  
  458. {
  459.       short            itemHit;
  460.       StringHandle    displayMessage;
  461.       Str255            displayMessageString;
  462.   
  463.       SetCursor(&qd.arrow);
  464.   
  465.       if (result)  
  466.       displayMessage = GetString (201);
  467.     else
  468.       displayMessage = GetString (202);
  469.     
  470.     
  471.        if (displayMessage != nil)
  472.       BlockMove(*displayMessage, &displayMessageString, (long)*displayMessage[0]+1L);
  473.      else
  474.        AlertUser();
  475.        
  476.     ParamText (displayMessageString, "\p ", "\p ", "\p ");
  477.     
  478.     itemHit = NoteAlert(rLandscapeAlert, nil);
  479.     
  480. }    //  end of ShowLandscapeResults
  481.  
  482.  
  483.  
  484.  
  485. //------ IsLandscapeSet -------------------------------------------------------------
  486. //
  487. //    IsLandscapeSet will determine if the user has selected landscape orientation 
  488. //    from the Style dialog. If the user has selected landscape orientation, we will 
  489. //    return "true" to the calling function. Otherwise, return "false".
  490. //
  491.  
  492. void IsLandscapeSet (THPrint thePrRecHdl)
  493.  
  494. {
  495.        TGetRotnBlk    GetRotRec;
  496.     
  497.        GetRotRec.iOpCode = getRotnOp;
  498.       GetRotRec.hPrint = thePrRecHdl;
  499.  
  500.       PrGeneral ((Ptr) &GetRotRec);    
  501.      
  502.     //  If the landscape opcode is NOT implemented by the current printer driver,
  503.     //  set the flag to true.  This flag will preent the calling of this function
  504.     //  until the printer driver is changed...
  505.  
  506.     if (GetRotRec.iError == OpNotImpl)
  507.       gLandscapeOpImpl = false;
  508.       
  509.       
  510.     //    We now have the result from our call to PrGeneral, but we check all
  511.     //    known errors to make sure that PrGeneral was successful and there
  512.     //    have not been any errors encountered from printing land.
  513.  
  514.     if (GetRotRec.iError == noErr && PrError() == noErr && GetRotRec.fLandscape)
  515.        ShowLandscapeResults (true);
  516.     else if (GetRotRec.iError != OpNotImpl)
  517.            ShowLandscapeResults (false);
  518.  
  519. }    //  end of IsLandscapeSet
  520.  
  521.  
  522.  
  523.  
  524. //------ drawStuff ------------------------------------------------------------------
  525. //
  526. //    drawStuff will create the graph and draw it directly to the current port that is
  527. //    passed in via the prPort variable. It will draw all of the coordinates and font
  528. //    sizes at the prScale value.  For example, on the ImageWriter, the scaling is 2X 
  529. //  the screen. On the ImageWriter LQ, three times and on the LaserWriter, four times.
  530. //    TBy using a scale factor ensures that you do NOT print "micro" images or text when 
  531. //    the SetRsl opcode is used.
  532. //
  533. //  The number of line segments used to draw our graph is is directly proportional to 
  534. //    the gScale factor (i.e. prScale), which is why you will get smoother curves when 
  535. //    using the SetRsl opcode on any printer driver that supports it. For example, on 
  536. //    the LaserWriter II/NT the gScale factor is 4; which means for a given line segment 
  537. //    in the curve, you will have 3 additional points when printing with SetRsl.
  538. //
  539.  
  540. void drawStuff ( prPort, prScale)
  541.  
  542. GrafPtr        prPort;
  543. short        prScale;
  544. {
  545.     short        theFontID;
  546.     Rect        graphRect;
  547.  
  548.     short        loop,
  549.                 plotX, 
  550.                 plotY;
  551.     
  552.     extended     x  = -2.5, 
  553.                 y;
  554.     Str255        scaleValueStr;
  555.  
  556.     CGrafPtr    currPort;
  557.     GDHandle    currDev;
  558.     
  559.  
  560.     GetGWorld (&currPort, &currDev);
  561.  
  562.     SetGWorld ((CGrafPtr) prPort, currDev);
  563.  
  564.     SetRect (&graphRect, 0, 0, 500, 300);
  565.     
  566.     EraseRect (&(prPort->portRect));
  567.     
  568.     
  569.     // Print the heading of the graph...
  570.     
  571.     GetFNum("\pHelvetica", &theFontID);
  572.     TextFont(theFontID);
  573.     TextSize (FontSize * prScale);
  574.     MoveTo ( 120 * prScale, 55 * prScale);
  575.     DrawString ("\pPrinting at ");
  576.     
  577.     if (gMaxDPI == 0)
  578.       NumToString ((**gPrRecHdl).prInfo.iHRes, &scaleValueStr);
  579.     else  NumToString (gMaxDPI, &scaleValueStr);
  580.     
  581.     DrawString (scaleValueStr);
  582.  
  583.     MoveTo (201 * prScale , 55 * prScale);
  584.     DrawString ("\pdpi");
  585.     
  586.     
  587.     //  Draw the axes of the graph...
  588.     
  589.     PenSize(2 * prScale, 1 * prScale);
  590.  
  591.     MoveTo ((graphRect.left + 20) * prScale, (graphRect.top + 45) * prScale);
  592.     LineTo ((graphRect.left + 20) * prScale, (graphRect.bottom - 45) * prScale);
  593.     MoveTo ((graphRect.left + 20) * prScale, ((graphRect.bottom - graphRect.top)/2) * prScale);
  594.     LineTo ((graphRect.right - 170) * prScale, ((graphRect.bottom - graphRect.top)/2) * prScale);
  595.     
  596.     
  597.     //  Draw the lower curve...
  598.     
  599.     MoveTo ((graphRect.left + 20) * prScale, ((graphRect.bottom - graphRect.top)/2) * prScale);
  600.     PenSize(1,1);
  601.     
  602.     plotX = (graphRect.left + 20) * prScale;
  603.     plotY = ((graphRect.bottom - graphRect.top - 85)/2) * prScale;
  604.  
  605.     
  606.     // The number of line segments is directly proportional to the gScale factor (i.e. prScale), 
  607.     // which is why you will get smoother curves when using the SetRsl opcode on any printer 
  608.     // driver that supports it. For example, on the LaserWriter II/NT the gScale factor is 4;
  609.     // which means for a given line segment in the curve, you will have 3 additional points
  610.     // when printing with SetRsl.
  611.     
  612.     for (loop = 1; loop < 20 * prScale; loop++)
  613.       {
  614.          y = (sin (x/2)) * 35 + 2;
  615.   
  616.         plotY = (plotY + ((int) y));
  617.         plotX = (plotX + ((int) x));
  618.       
  619.           if (plotX >= (graphRect.left + 22) * prScale)
  620.           LineTo (plotX, plotY);
  621.  
  622.         plotX += 10;
  623.     
  624.         x += 1.0 / (float) prScale;
  625.       }
  626.  
  627.  
  628.     //  Draw the lower curve
  629.     x  = 0;
  630.       
  631.      MoveTo ((graphRect.left + 20) * prScale, ((graphRect.bottom - graphRect.top)/2) * prScale);
  632.  
  633.     plotX = (graphRect.left + 20) * prScale;
  634.     plotY = ((graphRect.bottom - graphRect.top - 60)/2) * prScale;
  635.  
  636.     for (loop = 1; loop < 18 * prScale; loop++)
  637.       {
  638.          y = (cos (x/2)) * 40 + 2;
  639.   
  640.         plotY = (plotY + ((int) y));
  641.         plotX = (plotX + ((int) x));
  642.       
  643.           if (plotX >= (graphRect.left + 22) * prScale)
  644.           LineTo (plotX, plotY);
  645.  
  646.         plotX += 10;
  647.     
  648.         x += 1.0 / (float) prScale;
  649.       }
  650.  
  651.    SetGWorld (currPort, currDev);
  652.  
  653. }    // end of drawStuff
  654.  
  655.  
  656.  
  657.  
  658. //------ copyBitsMyGraph -------------------------------------------------------------
  659. //
  660. //    copyBitsMyGraph will create a off-screen world with a call to 32-bit QuickDraw's
  661. //  NewGWorld.  We check to make sure that 32-bit QuickDraw is present BEFORE this 
  662. //  function is called.  We will then draw directly into the the off-screen world with a call
  663. //    to drawStuff.  CopyBits will then be used to copy the contents of the off-screen world
  664. //    into the printer's GrafPort.  Remember, when you use the DraftBits opcode, it will 
  665. //  only print text, bitmaps, and pixmaps.  If we did NOT use the CopyBits call, only the 
  666. //    heading of the graph would be printed...
  667. //
  668.  
  669. void copyBitsMyGraph (TPPrPort printPort)
  670. {
  671.     Rect        graphRect;
  672.     QDErr        QDError;
  673.     GDHandle    currDev;
  674.     CGrafPtr    currPort;
  675.     GWorldPtr    myDrawingPort;
  676.  
  677.  
  678.     GetGWorld (&currPort, &currDev);
  679.         
  680.     SetRect (&graphRect, 0, 0, 500 * gScale, 300 * gScale);
  681.     
  682.     QDError = NewGWorld(&myDrawingPort, 1, &graphRect, nil, nil, 0);
  683.     
  684.     if (QDError == noErr)
  685.       {
  686.         if (!LockPixels (myDrawingPort->portPixMap))
  687.           AlertUser ();
  688.         
  689.         //  Draw the graph into the off-screen world...
  690.           drawStuff (myDrawingPort, gScale);
  691.         
  692.         
  693.         //  Set the port to the printer's GrafPort and CopyBits the off-screen
  694.         //  world into the printer's GrafPort.
  695.         
  696.         SetPort (&(printPort->gPort));
  697.           CopyBits ((BitMap *) &myDrawingPort->portPixMap, &(printPort->gPort.portBits), 
  698.                   &myDrawingPort->portRect, &myDrawingPort->portRect, srcCopy, nil);
  699.         UnlockPixels (myDrawingPort->portPixMap);
  700.         
  701.       }
  702.      else AlertUser ();
  703.     
  704.     if (myDrawingPort != nil)
  705.          DisposeGWorld (myDrawingPort);
  706.  
  707.     SetGWorld (currPort, currDev);
  708.     
  709. }    // end of copyBitsMyGraph
  710.  
  711.  
  712.  
  713.  
  714.  
  715. //------ comparePrintRecords ---------------------------------------------------------
  716. //
  717. //  We need to determine if the print has changed, since the last time we
  718. //  called the PageSetup or Print Job dialog.  If it has, we want to update the print
  719. //    record with the PrGeneral selections from the PrGeneral menu.  But, before we call
  720. //  PrGeneral to set the requested opcodes, we will call testForPrGeneral to make sure
  721. //  that it is supported by the "new" printer driver.  We only worry about the SetRsl and
  722. //  DraftBits opcodes at this point, because they effect the appearance of the PageSetup 
  723. //  and Print Job, if PrGeneral is available.
  724. //
  725.  
  726. void comparePrintRecords ()
  727. {
  728.     THPrint     localPrRecHdl;
  729.     short        latestDriverVers;
  730.     
  731.  
  732.     // Create a new print record with default settings
  733.     
  734.     localPrRecHdl = (THPrint) NewHandle(sizeof(TPrint));
  735.     if (MemError() == noErr && localPrRecHdl != nil)
  736.     {
  737.         PrintDefault (localPrRecHdl);
  738.     
  739.         latestDriverVers = PrDrvrVers ();
  740.     
  741.         //  This is an example of the right place to use wDev. We are only using wDev to 
  742.         //  determine, if the print records are the same type. NOT to check for specific
  743.         //  functionality which would be a bad idea for compatibility with unknown printers.
  744.         
  745.         if (PrError () == noErr)
  746.          {
  747.           if ((((**gPrRecHdl).prStl.wDev) >> 8) != (((**localPrRecHdl).prStl.wDev) >> 8)
  748.                || (latestDriverVers != gOriginalDriverVers))
  749.            { 
  750.              //  Set the print record to default settings for the "new" printer...
  751.     
  752.              PrintDefault (gPrRecHdl);
  753.             
  754.              //  Reset the value of gOriginalDriverVers
  755.     
  756.              gOriginalDriverVers = latestDriverVers;
  757.     
  758.     
  759.              //  Reset gMaxDPI to enable the loop in setMaxResolution to find the correct 
  760.              //  maximum resolution
  761.     
  762.              gMaxDPI = 0;
  763.              
  764.              
  765.              //  Reset all of the opcode implementation flags.  We now have a new printer
  766.              //  driver, therefore we need to determine which opcodes are supported.
  767.              
  768.              gLandscapeOpImpl = true;
  769.              gDraftBitsOpImpl = true;
  770.              gSetRslOpImpl = true;
  771.              
  772.              
  773.              // Test to determine, if the "new" printer driver supports PrGeneral before
  774.              // updating the print record with the requested PrGeneral opcodes...
  775.     
  776.              if (PrError () == noErr)
  777.                 gPrGeneralLives = testForPrGeneral ();
  778.              else AlertUser ();  
  779.     
  780.              
  781.              // Call the appropriate PrGeneral opcodes, determined by the PrGeneral menu...
  782.     
  783.              if (PrError () == noErr && gPrGeneralLives)
  784.                {
  785.                 if (gUseDraftBits && gDraftBitsOpImpl)  doDraftBits();
  786.             
  787.                 if (gHighResolutionON && gSetRslOpImpl)  doSetRsl();     
  788.                }
  789.            }
  790.          
  791.            if (localPrRecHdl != nil)  DisposHandle((Handle) localPrRecHdl);
  792.          }
  793.     
  794.         // An error has occurred, close the Print Manager and alert the user    
  795.         
  796.         else   
  797.           {
  798.            PrClose ();
  799.            if (localPrRecHdl != nil)  DisposHandle((Handle) localPrRecHdl);
  800.            AlertUser ();
  801.           }
  802.     }
  803.     
  804.     // An error occurred allocating new print record, close the Print Manager and alert the user
  805.     else
  806.     {
  807.         PrClose ();
  808.         AlertUser();
  809.     }
  810.  
  811. }    //  end of comparePrintRecords
  812.  
  813.  
  814.  
  815.  
  816. //------ PresentStyleDialog ----------------------------------------------------------
  817. //
  818. //  We will present the PageSetup dialog requested by the user, but we want to make sure
  819. //  that the printer driver has not changed.  Why? If the user has changed the printer 
  820. //  driver via the Chooser, we want to update the print record with the requested
  821. //  PrGeneral opcodes, if the "new" (current) printer driver supports PrGeneral.
  822. //  Remember, the SetRsl and DraftBits opcodes change the appearence of the Page Setup 
  823. //  dialog, therefore we want to make the PrGeneral calls before presenting the dialog.
  824. //
  825.  
  826. void PresentStyleDialog ()
  827. {
  828.     if ( gPrRecHdl ) 
  829.      {
  830.         PrOpen();
  831.         
  832.         // A print error occurred, close up the Print Manager and notify the user...
  833.     
  834.         if (PrError () != noErr)
  835.           {
  836.             PrClose();
  837.             AlertUser ();
  838.           }
  839.          else 
  840.            {
  841.             // Check to make sure that the user has not changed the printer driver 
  842.            
  843.             comparePrintRecords ();        
  844.  
  845.             PrStlDialog(gPrRecHdl);
  846.             
  847.             // Check for landscape orientation, if the user has requested the test via
  848.             // the PrGeneral Menu and PrGeneral exists for the current printer driver...
  849.             
  850.             if (gCheckForLandscape && gPrGeneralLives && gLandscapeOpImpl)  
  851.               IsLandscapeSet (gPrRecHdl);
  852.         
  853.             PrClose();
  854.            }
  855.      }
  856.      else AlertUser ();    // The gPrRecHdl is nil and it should not be, alert the user
  857.  
  858. }    //  end of PresentStyleDialog
  859.  
  860.  
  861.  
  862.  
  863. //------ PrintThis -------------------------------------------------------------------
  864. //
  865. //  PrintThis is your basic print loop.  If any error occurs during this function 
  866. //  (i.e. print time) the user will be notified via a call to AlertUser.  But, before we 
  867. //  alert the user, we will call the corresponding close call(s) for all of the open 
  868. //  call(s) (i.e. PrOpenDoc  --> PrCloseDoc) and close up the Print Manager.  For a 
  869. //  complete industrial strength print loop, see Tech Note #161.  
  870. //
  871.  
  872. void PrintThis()
  873. {
  874.     short            NumberOfPages;
  875.     TPPrPort        printPort;
  876.     OSErr            err;
  877.     short            i;
  878.     TPrStatus         Status;
  879.     GDHandle        currDev;
  880.     CGrafPtr        currPort;
  881.  
  882.     GetGWorld (&currPort, &currDev);
  883.     
  884.     if ( gPrRecHdl ) {
  885.         PrOpen();
  886.         if ( PrError() == noErr ) { 
  887.         
  888.           // Determine if the printer driver has changed...
  889.           
  890.           comparePrintRecords ();     
  891.             
  892.           if ( PrJobDialog(gPrRecHdl)) 
  893.             
  894.             if ( PrError() == noErr ) {
  895.                           
  896.               NumberOfPages = (**gPrRecHdl).prJob.iCopies;
  897.                         
  898.               printPort = PrOpenDoc(gPrRecHdl,nil,nil);
  899.                         
  900.               if ( PrError() == noErr ) {
  901.                 for ( i = 1; i <= NumberOfPages; i++) {
  902.                    PrOpenPage(printPort,nil);
  903.                                 
  904.                    if ( !(err = PrError()) ) {
  905.                     
  906.                     //  If the user has selected the DraftBits menu item,
  907.                     //  we will call copyBitsMyGraph, which will ensure that 
  908.                     //  our graph will be printed "draft" on the ImageWritter. If
  909.                     //  we just called drawStuff all of the time, the graph would 
  910.                     //  NOT print when "draft" printing was selected.
  911.  
  912.                     if (gUseDraftBits)
  913.                       copyBitsMyGraph (printPort);
  914.                     else drawStuff (&(printPort->gPort), gScale);
  915.                     }
  916.                                 
  917.                    PrClosePage(printPort);
  918.                    }
  919.                    PrCloseDoc(printPort);
  920.                 }
  921.                         
  922.              if ((**gPrRecHdl).prJob.bJDocLoop == bSpoolLoop && PrError() == noErr)
  923.                 PrPicFile(gPrRecHdl,nil,nil,nil,&Status);
  924.                         
  925.              err = PrError();
  926.             
  927.            PrClose();
  928.            if ( err )
  929.              AlertUser();
  930.             }
  931.           }
  932.         }
  933.     
  934.     SetGWorld (currPort, currDev);
  935.     
  936. }    //  end of PrintThis
  937.